tags:
- Build
what is a building system do?
一个简单的makefile. 前面的都是变量,直到 all:
CC=gcc # complier variable
INCDIRS=-I #
OPT=-O0 # optimization variable
CFLAGS=-Wall -Wextra -g $(INCDIRS) $(OPT)
CFLAGS=x.c y.c
OBJECTS=x.o y.o
BINARY=bin
all: $(BINARY)
$(BINARY): $(OBJECTS)
$(CC) -o $@ $^
%.o:%.c # make feature, % is a wildcard (repersenting everything)
$(CC) $(CFLAGS) -c -o $@ $^
clean:
rm -rf $(BINARY) $(OBJECTS)
build rule: all: $(BINARY) 就是一个build rule(这里的target和dependencies有何联系?)
all directive, 当你用make all就会转到makefile中的 (默认情况下只用 make 会转到第一个 rule)
上面的makefile的意思就是说当你在终端 make all 的时候,你就会转到 $(BINARY): $(OBJECTS)。但是BINARY depends on OBJECTS,也就是你要构建bin你就需要先得到所有的 .o 文件。如果没有,就会执行 %.o:%.c (.o 文件 依赖 .c 文件) @ 表示 LHS (.o) ^表示RHS (.c)
target: dependencies 如果所有依赖项都满足就执行 command
command
即使你有 x.o 如果你修改了源文件,make 一个新的 x.o 将会被编译(build system的第二个事情,只做需要的事情)
需要先介绍不用variable会怎么样。
用variable之后makefile才会做需要做的事情吗?
如果头文件修改,makefile不会察觉到有什么修改了(因为.h没有依赖项
第三个例子: featureful makefile---我们将头文件都放在include文件夹中,将库放到lib文件夹中。我们将include作为依赖项,当我们修改.h文件时,makefile就能够察觉到有东西被修改了
BINARY=bin
CODEDIR=. lib
INCDIRS=. ./include/ # can be listed
CC=gcc
OPT=-O0
# generate files that encode make rules for the .h dependencies
DEPFLAGS=-MP -MD # let make work with compiler?是这样么
CFLAGS=-Wall -Wextra -g $(foreach D, $(INCDIRS),-I$(D) $(OPT) $(DEPFLAGS))
CFILES=$(foreach D,$(CODEDIRS),$(wildcard $(D)/*.c))
OBJECTS=$(patsubst %.c,%.o,%(CFILES))
DEPFILES=$(patsubst %.c,%.d,%(CFILES))
all: $(BINARY)
$(BINARY): $(OBJECT)
$(CC) -o $@ $^
%.o:%.c # make feature, % is a wildcard (repersenting everything)
$(CC) $(CFLAGS) -c -o $@ $< # only want .c dependency here thus $<
clean:
rm -rf $(BINARY) $(OBJECTS) $(DEPFILES)
distribute: clean
tar zcvf dist.tgz *
diff
# include the dependency
-include $(DEPFILES)
依赖项 (dependencies)
# GCC flags first
target [targets...]: [components...]
[ command 1]
# ...
[ command n]
special commands
-
@
+
macros and variables
MACRO1 = 12
COMPILE = gcc *.c
gcc:
$(COMPILE)
multi line commands
在makefile中,每行命令都默认允许在一个独立的shell终端中,也就是说在 Badlisting 中
如果需要多个命令共享同一个上下文(例如切换目录后运行操作),需要将它们合并到一个 Shell 会话中,通常使用反斜杠 \
或 &&
分号用于在同一行中分隔多个命令。例如:
Badlisting:
cd dir
ls
Goodlisting:
cd dir;\ # same as cd dir && ls
ls
makefile 也可以用于 testing
makefile的好处就是只编译修改了的.c/.cpp文件并生成修改后的.o文件。节省编译时间。一个标准的makefile可能是这样的:
CC = gcc
INCDIRS = -I.
OPT = -O0
CFLAGS = -Wall -Wextra -g $(INCDIRS) $(OPT)
CFILES =
OBJECTS =
BINARY =
all: $(BINARY)
clean:
random:
date
sl
mkdir useless
cd useless ;\
cd..
all: # all 是干嘛的?
help: #这些是按照顺序执行的么
CC = GCC
all:
$(CC) file.c -o proj
debug:
debug: CC += -g -DDEBUG
在构建系列的
头文件:存放声明和内联化的函数/变量(constexpr/consteval...)declarations
因为内联后的符号没有定义
These files contain declarations and inline functions/variables. For example, constexpr and consteval declarations are often found in header files. Declarations inform the compiler about the existence and type of functions or variables without providing the full implementation.
Source Files (源文件): These files contain definitions. A definition is a specific type of declaration that provides complete information about an entity, including its implementation.
foo.h
int foo(int n); //A declaration, no function body.
extern int e; // A non-defining declaration.
foo.cpp
#include "foo.h"
int foo(int n) // A definition, we have the function body after this.
{
// Function implementation goes here.
}
int a; // Definition without initialization
int b = 10; // Definition with initialization
static int c = 10; // A file-scope static definition
extern int d = 10;
other.cpp
int e = 10; //
源文件中存放definitions, definition is a specific type of declaration. Definition gives a set of informations about the entity but no verse visa
ProjectName/
├── include/ # Header file
│ ├── main.h
│ └── utils.h
├── src/ # Source file
│ ├── main.cpp
│ └── utils.cpp
├── lib/ # Libraries
│ └── mylib.a
├── build/ # Object files
│ └── (object files, executables)
├── tests/ # Testing code
│ └── test_main.cpp
├── CMakeLists.txt # CMake build file
├── Makefile # Makefile build file
└── README.md # Intro to the project
这节课用建立 shell 文件构建代码
gcc ....
gcc ....
gcc x.o y.o -o bin
用上面的方法的劣势就是每次构建都需要整个的编译,而不是选择性编译
下节课用 makefile